using System.Linq;

namespace EFS.Common.Values
{
	/// Class Enum
	public class Enum<TEnum> : EFS.Common.Values.Int32, EFS.Common.Values.Interfaces.Enum
	where TEnum : struct, System.IComparable, System.IFormattable, System.IConvertible
	{
		#region Constructors

		/// Static constructor
		static Enum()
		{
			// check predicate
			if (!typeof(TEnum).IsEnum)
			{
				throw new System.NotSupportedException("TEnum must be an enumerated type");
			}

			// init enum values
			EnumValues = (from field in typeof(TEnum).GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static) where field.IsLiteral select (TEnum)field.GetValue(null)).ToArray();
		}

		/// Implicit constructor
		public Enum()
		{
		}

		/// Explicit constructor
		public Enum(System.Int32 value)
			: base(value)
		{
		}

		/// Explicit constructor
		public Enum(TEnum value)
			: base((System.Int32)((System.ValueType)value))
		{
		}

		#endregion

		#region Properties
		/// Property EnumValues: Get, Set
		public static TEnum[] EnumValues { get; private set; }
		#endregion

		#region Usage

		/// Property InnerValueEnumReadable
		public System.String InnerValueEnumReadable
		{
			get
			{
				// create string enum
				EFS.Common.StringEnum stringEnum = new EFS.Common.StringEnum(typeof(TEnum));

				// set
				System.String retValue = stringEnum.GetStringValue(InnerValueEnum.ToString());
				if (!EFS.Common.Verify.String(retValue))
				{
					retValue = InnerValueEnum.ToString();
				}

				// ok
				return retValue;
			}
		}

		/// Property InnerValueEnum
		public TEnum InnerValueEnum
		{
			get
			{
				// cast to TEnum
				return (TEnum)(System.ValueType)base.InnerValue;
			}
			set
			{
				// Cast to Int32
				base.InnerValue = (System.Int32)((System.ValueType)value);
			}
		}

		/// Property InnerValueEnum
		public System.Object InnerObjectEnum
		{
			get
			{
				// check null
				if (IsNull)
				{
					// null
					return null;
				}

				// cast to enum
				return (TEnum)(System.ValueType)base.InnerObject;
			}
			set
			{
				// check null
				if (null == value)
				{
					SetNull();
				}
				else
				{
					// cast to Int32
					base.InnerObject = (System.Int32)(System.ValueType)value;
				}
			}
		}

		/// <summary>
		/// Inner enum type
		/// </summary>
		public System.Type InnerTypeEnum
		{
			get { return typeof(TEnum); }
		}

		/// Retrieves the safe value
		public TEnum GetSafeEnum(TEnum @default)
		{
			// return default
			if (IsNull)
			{
				return @default;
			}

			// ok
			return InnerValueEnum;
		}

		/// Safe equals
		public System.Boolean EqualsSafeEnum(TEnum value)
		{
			// return default
			if (IsNull)
			{
				return false;
			}

			// ok
			return InnerValueEnum.Equals(value);
		}
		#endregion
	}

}